package com.leonzhangxf.spel.reference;

import com.leonzhangxf.spel.reference.bean.Inventor;
import com.leonzhangxf.spel.reference.bean.PlaceOfBirth;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.SimpleEvaluationContext;

/**
 * Safe Navigation Operator
 *
 * The safe navigation operator is used to avoid a NullPointerException and comes from the Groovy language.
 * Typically, when you have a reference to an object,
 * you might need to verify that it is not null before accessing methods or properties of the object.
 * To avoid this, the safe navigation operator returns null instead of throwing an exception.
 *
 * @author leonzhangxf
 * @date 20190427
 */
public class SafeNavigationOperator {

    public static void main(String[] args) {
        ExpressionParser parser = new SpelExpressionParser();
        EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build();

        Inventor tesla = new Inventor("Nikola Tesla", "Serbian");
        tesla.setPlaceOfBirth(new PlaceOfBirth("Smiljan"));

        String city = parser.parseExpression("PlaceOfBirth?.City").getValue(context, tesla, String.class);
        // Smiljan
        System.out.println(city);

        tesla.setPlaceOfBirth(null);
        city = parser.parseExpression("PlaceOfBirth?.City").getValue(context, tesla, String.class);
        // null - does not throw NullPointerException!!!
        System.out.println(city);

        try {
            // null - throw SpelEvaluationException!!!
            city = parser.parseExpression("PlaceOfBirth.City").getValue(context, tesla, String.class);
            System.out.println(city);
        } catch (SpelEvaluationException ex) {
            System.out.println(ex.getMessage());
        }
    }
}
